package cn.lili.modules.kit.plugin.wechat;

import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.lili.common.context.ThreadContextHolder;
import cn.lili.common.enums.ResultCode;
import cn.lili.common.exception.ServiceException;
import cn.lili.common.properties.ApiProperties;
import cn.lili.common.thread.ThreadConfig;
import cn.lili.common.utils.CurrencyUtil;
import cn.lili.common.utils.GsonUtils;
import cn.lili.common.utils.ResultUtil;
import cn.lili.common.utils.StringUtils;
import cn.lili.common.vo.ResultMessage;
import cn.lili.exchange.AmqpExchangeProperties;
import cn.lili.modules.kit.Payment;
import cn.lili.modules.kit.core.PaymentHttpResponse;
import cn.lili.modules.kit.core.enums.RequestMethodEnums;
import cn.lili.modules.kit.core.kit.WxPayKit;
import cn.lili.modules.kit.plugin.alipay.AliPayApi;
import cn.lili.modules.kit.plugin.wallet.WalletPlugin;
import cn.lili.modules.kit.plugin.wechat.model.PartnerTransactionsResult;
import cn.lili.modules.order.order.client.OrderClient;
import cn.lili.modules.payment.entity.dos.OutOrderLog;
import cn.lili.modules.payment.entity.dos.PaymentCallbackLog;
import cn.lili.modules.payment.entity.dos.PaymentLog;
import cn.lili.modules.payment.entity.dos.RefundLog;
import cn.lili.modules.payment.entity.dto.PaymentWakeupParam;
import cn.lili.modules.payment.entity.enums.PaymentMethodEnum;
import cn.lili.modules.payment.entity.enums.PaymentSceneEnums;
import cn.lili.modules.payment.service.*;
import cn.lili.modules.payment.wechat.enums.WechatApiEnum;
import cn.lili.modules.payment.wechat.enums.WechatDomain;
import cn.lili.modules.payment.wechat.model.Amount;
import cn.lili.modules.payment.wechat.model.RefundModel;
import cn.lili.modules.system.entity.dto.payment.AlipayPaymentSetting;
import cn.lili.modules.system.entity.dto.payment.WechatPaymentSetting;
import cn.lili.modules.wallet.service.WalletService;
import cn.lili.util.ToolsUtil;
import com.alipay.api.internal.util.AlipaySignature;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Map;
import java.util.Objects;

@Slf4j
@Component
public class WechatPluginNew extends WalletPlugin implements Payment {

    @Resource
    private ApiProperties apiProperties;
    @Resource
    private WechatPluginNewManage wechatPluginNewManage;
    @Resource
    private PaymentLogService paymentLogService;
    @Resource
    private RefundLogService refundLogService;
    @Resource
    private ThreadConfig threadConfig;
    @Resource
    private IPaymentCallbackLogService paymentCallbackLogService;

    public WechatPluginNew(ApplicationEventPublisher applicationEventPublisher,
                           AmqpExchangeProperties amqpExchangeProperties, WalletService walletService,
                           PaymentLogService paymentLogService, OutOrderLogService outOrderLogService,
                           OutOrderDetailLogService outOrderDetailLogService,
                           PaymentSubsidiesService paymentSubsidiesService,
                           PaymentUrbanSubstationCommissionService paymentUrbanSubstationCommissionService, OrderClient orderClient) {
        super(applicationEventPublisher, amqpExchangeProperties, walletService, paymentLogService,
                outOrderLogService, outOrderDetailLogService, paymentSubsidiesService,
                paymentUrbanSubstationCommissionService, orderClient);
    }

    /**
     * H5支付
     */
    @Override
    public ResultMessage<Object> h5pay(PaymentWakeupParam paymentWakeupParam) {
        log.info("paymentWakeupParam------{}",paymentWakeupParam);
        //组织请求支付参数
        String notifyUrl = notifyWechat(apiProperties.getBuyer(), PaymentMethodEnum.WECHAT);
        //WechatApiEnum wechatApiEnum = Boolean.TRUE.equals(paymentWakeupParam.getIsCombine()) ? WechatApiEnum.COMBINE_TRANSACTIONS_H5 : WechatApiEnum.H5_PAY;
        //WechatApiEnum wechatApiEnum = Boolean.TRUE.equals(paymentWakeupParam.getIsCombine()) ? WechatApiEnum.COMBINE_TRANSACTIONS_NATIVE : WechatApiEnum.NATIVE_PAY;
        WechatApiEnum wechatApiEnum = WechatApiEnum.H5_PAY;

        PaymentHttpResponse response;
        //发起支付请求
        if(Boolean.TRUE.equals(paymentWakeupParam.getIsCombine())) {
            response = wechatPluginNewManage.wechatPay2(paymentWakeupParam, notifyUrl, wechatApiEnum);
        }else{
            response = wechatPluginNewManage.wechatPay(paymentWakeupParam, notifyUrl, wechatApiEnum);
        }

        //结果处理
        log.info("response {}", com.alibaba.fastjson.JSONObject.toJSONString(response));
        log.info("wechatPluginNewManage.getPlatformCert {}", wechatPluginNewManage.getPlatformCert());
        boolean verifySignature = WxPayKit.verifySignature(response, wechatPluginNewManage.getPlatformCert());

        log.info("统一下单响应 {}", com.alibaba.fastjson.JSONObject.toJSONString(response));
        log.info("verifySignature == {}", verifySignature);
        if (!verifySignature) {
            throw new ServiceException(ResultCode.WECHAT_CERT_ERROR);
        }
        return ResultUtil.data(response.getBody());
    }

    public static void main(String[] args) {
        JSONObject jsonObject = JSONUtil.parseObj("{\"isCombine\":\"200\"}");
        System.out.println("200".equals(jsonObject.getStr("isCombine")));
    }
    /**
     * 支付回调通知
     * */
    @Override
    public void paymentNotify() throws Exception {
        PaymentCallbackLog paymentCallbackLog = new PaymentCallbackLog();
        try {
            String plainText = wechatPluginNewManage.getPlaintext();
            log.info("微信支付通知明文 {}", plainText);
            //支付日志记录
            paymentCallbackLog.setPaycallbackObj(plainText);
            //是否合单支付
            JSONObject jsonObject = JSONUtil.parseObj(plainText);
            Boolean isCombine = jsonObject.containsKey("combine_out_trade_no");
            /** 保存微信回调记录**/
            Objects.requireNonNull(threadConfig.getAsyncExecutor()).execute(() -> {
                PartnerTransactionsResult transactionsResult = GsonUtils.fromJson(plainText, PartnerTransactionsResult.class);
                PaymentLog paymentLog = paymentLogService.getPaymentLogByOutTradeNo(transactionsResult.getOutTradeNo());
                //保存支付回调通知结果日志
                paymentCallbackLog.setPassbackParams("WHCHAT_PAY");
                paymentCallbackLog.setOutTradeNo(transactionsResult != null && StrUtil.isNotEmpty(transactionsResult.getOutTradeNo()) ? transactionsResult.getOutTradeNo() : "");
                paymentCallbackLog.setExecResult(paymentLog != null && StrUtil.isNotEmpty(paymentLog.getOrderSn()) ? ("orderSn:" + paymentLog.getOrderSn()) : "");
                paymentCallbackLog.setMethodName("WechatPluginNew.paymentNotify");
                paymentCallbackLogService.save(paymentCallbackLog);
            });

            boolean isCombine2 = false;
            if(jsonObject.get("attach") != null && !"".equals(jsonObject.get("attach"))){
                log.info("jsonObject.getJSONObject(attach).get(isCombine),{}",jsonObject.getJSONObject("attach").get("isCombine"));
                isCombine2 = "200".equals(jsonObject.getJSONObject("attach").getStr("isCombine"));
            }
            if (Boolean.TRUE.equals(isCombine) || isCombine2) {
                //合单回调
                wechatPluginNewManage.publicNotify2(plainText);
            }else{
                //普通订单回调
                wechatPluginNewManage.publicNotify(plainText);
            }

        } catch (Exception e) {
            log.error("WechatPluginNew.paymentNotify 支付回调同步通知异常", e);
            Objects.requireNonNull(threadConfig.getAsyncExecutor()).execute(() -> {
                //保存支付回调通知结果日志
                paymentCallbackLog.setPassbackParams("WHCHAT_PAY.异常Exception:" + ToolsUtil.getExceptionSrintStackTrace(e));
                paymentCallbackLog.setPaycallbackObj(StrUtil.isNotEmpty(paymentCallbackLog.getPaycallbackObj()) ? paymentCallbackLog.getPaycallbackObj() : "无解析回调body");
                paymentCallbackLog.setExecResult("异常Exception");
                paymentCallbackLog.setMethodName("WechatPluginNew.paymentNotify");
                paymentCallbackLogService.save(paymentCallbackLog);
            });
            throw e;
        }
    }

    /**
     * 退款
     * */
    @Override
    public void refund(RefundLog refundLog) {
        try {
            Amount amount = new Amount().setRefund(CurrencyUtil.fen(refundLog.getPrice())).setTotal(CurrencyUtil.fen(refundLog.getPayPrice()));

            WechatPaymentSetting setting = wechatPluginNewManage.wechatPaymentSetting();
            PaymentLog paymentLog = paymentLogService.getPaymentLogByOrderSN(refundLog.getOrderSn());
            if (paymentLog == null) {
                throw new ServiceException(ResultCode.PAY_NOT_EXIST_ORDER);
            }

            //退款参数准备
            RefundModel refundModel = new RefundModel()
                    .setTransaction_id(refundLog.getTransactionId())
                    .setOut_refund_no(refundLog.getOutRefundNo())
                    .setReason(StringUtils.isNotEmpty(refundLog.getRefundReason())?refundLog.getRefundReason():"用户退款")
                    .setAmount(amount)
                    .setNotify_url(refundNotifyUrl(apiProperties.getBuyer(), PaymentMethodEnum.WECHAT));
            log.info("微信退款参数 {}", JSONUtil.toJsonStr(refundModel));
            PaymentHttpResponse response = WechatApi.v3(RequestMethodEnums.POST, WechatDomain.CHINA.toString(),WechatApiEnum.DOMESTIC_REFUNDS.toString(), setting.getMchId(), setting.getSerialNumber(), null, setting.getApiclient_key(), JSONUtil.toJsonStr(refundModel));
            log.info("微信退款响应 {}", response);
            //退款申请成功
            if (response.getStatus() == 200) {
                refundLog.setIsRefund(true);
                //非同步退款所以 200状态不做处理
            } else {
                //退款申请失败
                refundLog.setErrorMessage(response.getBody());
            }
            refundLogService.updateById(refundLog);
        } catch (ServiceException serviceException) {
            throw serviceException;
        } catch (Exception e) {
            log.error("微信退款申请失败", e);
        }

    }

    /**
     * 退款回调
     * */
    @Override
    public void refundNotify() {
        try {
            //获取通知明文
            String plainText = wechatPluginNewManage.getPlaintext();
            log.info("微信退款通知明文 {}", plainText);

            JSONObject jsonObject = JSONUtil.parseObj(plainText);

            if (("SUCCESS").equals(jsonObject.getStr("refund_status"))) {
                log.info("退款成功 {}", plainText);
                //校验服务器端响应
                String outTradeNo = jsonObject.getStr("out_refund_no");
                String refundId = jsonObject.getStr("refund_id");

                RefundLog refundLog = refundLogService.getByOutOrderNo(outTradeNo);

                if (refundLog != null) {
                    refundLog.setIsRefund(true);
                    refundLog.setRefundTransactionId(refundId);
                    refundLogService.updateById(refundLog);
                }

            } else {
                log.info("退款失败 {}", plainText);
                String outTradeNo = jsonObject.getStr("out_refund_no");
                String refundId = jsonObject.getStr("refund_id");


                RefundLog refundLog = refundLogService.getByOutOrderNo(outTradeNo);

                if (refundLog != null) {
                    refundLog.setRefundTransactionId(refundId);
                    refundLog.setErrorMessage("可前往【商户平台—>交易中心】，手动处理此笔退款");
                    refundLogService.updateById(refundLog);
                }
            }
        } catch (ServiceException serviceException) {
            throw serviceException;
        } catch (Exception e) {
            log.error("微信退款失败", e);
        }
    }
}
